home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / stcron3.lzh / AT.C next >
Encoding:
C/C++ Source or Header  |  1993-10-03  |  8.3 KB  |  329 lines

  1. /* AT: (c) Kees Lemmens, Netherlands; June 1993.
  2.  
  3. This tool can start a job fo one run in the background at a
  4. specified time.
  5. Behaviour is similar to the UNIX AT command,but the code was
  6. completely by myself.
  7.  
  8. There are 3 possibilities to specify the time :
  9.  
  10. - at now + 12minutes
  11.   at now + 3hours
  12.   at now + 2 days
  13.   at now + 1 week
  14.  
  15.   As you see you can omit the space between the timevalue and type.
  16.   
  17. - at 12:30
  18.  
  19.   If the time is earlier than the current time the job will run
  20.   next day at the specified time.
  21.  
  22. - at 12:30 27-3
  23.  
  24.   If the time is earlier than the current time the job will run
  25.   next year at the specified time.
  26.   
  27.   The command is read from stdin. Any CR or LF or Ctrl-D will finish
  28.   the command and submit the job to the Crondaemon.
  29.   In this way it is also possible to use a pipe and echo to specify
  30.   the command (only from a shell of course !):
  31.   
  32.       echo '/bin/ls -la' | at now + 2days
  33.   
  34.   Remarks:
  35.   
  36. - This program can only run if the CROND (also by me) is running in
  37.   the background of your (MULTITOS) ATARI.
  38.  
  39. - The files at.allow and at.deny are not implemented as I consider this
  40.   useless on a simple ATARI.
  41.   
  42. - The program needs a passwd file to check the username (which is read
  43.   from USERENV variable, process uid or from cmdline option -u <user>).
  44.  
  45. - The only valid timename is 'now'. So names like 'tomorrow', 'midnight'
  46.   and others that can be used on some UNIX systems are not allowed.
  47.  
  48.   Any questions or suggestions about this program can be send to:
  49.   lemmens@dv.twi.tudelft.nl
  50. */
  51.  
  52. #include "cron.h"
  53.  
  54. #include <stdio.h>
  55. #include <string.h>
  56. #include <stdlib.h>
  57. #include <ctype.h>
  58. #include <pwd.h>
  59. #include <time.h>
  60. #include <errno.h>
  61.  
  62. extern char *ux2dos(char *string);
  63. extern void PokeDaemon(char cmd);
  64.  
  65. static enum    { list, delete, newjob } Option=newjob;
  66. static char *Days[]   = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  67. static char *Months[] = {NULL,"Jan","Feb","Mar","Apr","May",
  68.                         "Jun","Jul","Aug","Sep","Okt","Nov","Dec"};
  69.  
  70. static void usage(void)
  71. {
  72.     fprintf(stderr,"usage: %s [-u user] [-l|-r <nr>|<time>]\n", PROGNAME);
  73.     fprintf(stderr," -l       : list all atjobs\n");
  74.     fprintf(stderr," -r <nr>  : remove jobnr <nr>\n");
  75.     fprintf(stderr," <time>   : read new job from stdin\n\n");
  76.     fprintf(stderr," timespec : 'now + <nr> minutes|hours|days|weeks'");
  77.     fprintf(stderr," or 'mm:hh [dd-mm]'\n");
  78.     exit(1);
  79. }
  80.  
  81. static int ParseArgs(int argc,char * argv[],char *User,int *JobId)
  82. {    char *tmp,uflag=0;
  83.     struct passwd *pwent;
  84.     int skip=1;    /* always skip argv[0] */
  85.  
  86.     while(--argc>0)            /* parse options */
  87.     {    if(*argv[1]=='-')
  88.         {    switch(*(++argv[1]))
  89.             { 
  90.             case 'u': 
  91.                 if(argv[2] == NULL || ! isalpha(*argv[2]))
  92.                     usage();
  93.                 strcpy(User, argv[2]);
  94.                 uflag=1;    
  95.                 argv++;    argc--;
  96.                 skip+=2;
  97.                 break;
  98.             case 'l':
  99.                 Option = list;
  100.                 skip++;
  101.                 break; 
  102.             case 'r':
  103.                 Option = delete;
  104.                 if(argv[2] == NULL || ! isdigit(*argv[2]))
  105.                     usage();
  106.                 *JobId = atoi(argv[2]);
  107.                 argv++;    argc--;
  108.                 skip+=2;
  109.                 break;
  110.             default:  usage();
  111.                 break;
  112.             }
  113.         }
  114.         argv++;
  115.     }    
  116.  
  117.     if(!uflag)    /* determine username */
  118.     {    *User = '\0';
  119.         if((tmp=getenv(USERENV)) != NULL)
  120.             strcpy(User,tmp);
  121.         else if((pwent = getpwuid(Pgetuid())) == NULL)
  122.             strcpy(User,pwent->pw_name);
  123.     }
  124.     if(getpwnam(User) == NULL)
  125.     {    fprintf(stderr,PROGNAME " : User unknown.\n");
  126.         exit(1);
  127.     }
  128.     return skip;
  129. }
  130.  
  131. static void ListCmd(char *User)
  132. {    char *dirname = ATDIR;
  133.     char atname[MAX_FNAME];
  134.     char *fileid;
  135.     int  x,min,hour,mday,mon,wday;
  136.     FILE *atjob;
  137.     long DirHandle;
  138.     struct dirent d_ent;
  139.  
  140.     if((DirHandle=opendir(ux2dos(dirname))) < 0)
  141.     {    printf("No jobs for %s\n",User);
  142.         exit(0);
  143.     }    
  144.  
  145.     /* Rem. : Dreaddir is MINT specific call */
  146.  
  147.     while(Dreaddir(sizeof(d_ent),DirHandle,&d_ent.d_ino) == 0L)
  148.     {
  149.         for(x=0;d_ent.d_name[x] != '\0';x++)
  150.             d_ent.d_name[x] = tolower(d_ent.d_name[x]);
  151.  
  152.         if(strncmp(d_ent.d_name,User,strlen(User)))
  153.             continue;    /* job from other user */
  154.     
  155.         sprintf(atname,"%s/%s",dirname,d_ent.d_name);
  156.  
  157.         if((atjob = fopen(ux2dos(atname),"r")) == NULL)
  158.         {    fprintf(stderr,"Read failed for %s\n",atname);
  159.             exit(1);
  160.         }
  161.  
  162.         if((fileid = strchr(d_ent.d_name,'.')) != NULL)
  163.             *fileid++ = '\0';    /* separate name and extension */
  164.         else
  165.         {    fprintf(stderr,"Illegal filename %s\n",atname);
  166.             continue;
  167.         }
  168.         if(fscanf(atjob,"%d%d%d%d%d",&min,&hour,&mday,&mon,&wday) < 5)
  169.         {    fprintf(stderr,"Invalid job in %s\n",atname);
  170.             continue;
  171.         }
  172.         fclose(atjob);
  173.  
  174.         printf("User: % 10s  Jobnr: %3.3s  ",d_ent.d_name,fileid);
  175.         printf("Starttime: %02d:%02d %s %s-%02d\n",hour,min,
  176.             Days[wday],Months[mon],mday);
  177.     }
  178. }
  179.  
  180. static void DeleteCmd(char *User,int JobId)
  181. {    extern    errno;
  182.     char    atname[MAX_FNAME];
  183.  
  184.     sprintf(atname, "%s/%s.%03d",ATDIR,User,JobId);
  185.     if (remove(ux2dos(atname)))
  186.     {    if (errno == ENOENT)
  187.             fprintf(stderr, "Job %d for %s not found\n",JobId, User);
  188.         else
  189.             perror(atname);
  190.         exit(1);
  191.     }
  192.     printf("Atjob %d for %s removed\n",JobId, User);
  193.  
  194.     PokeDaemon(EXTERNBUILD);    /* send a reread signal to daemon */
  195. }
  196.  
  197. static void TimeError(void)
  198. {    fprintf(stderr,"Invalid time specification\n");
  199.     exit(1);
  200. }
  201.  
  202. static struct tm *ParseJobTime(char *timemask)
  203. {    struct tm *attm;
  204.     time_t curti,atti;
  205.     long value;
  206.     char *dtstr,*tmstr,timesymbol;
  207.  
  208.     time(&curti);
  209.  
  210.     if(! strncmp("now",timemask,3))
  211.     {    atti = curti;
  212.         if((tmstr=strchr(timemask,'+')) == NULL)
  213.             TimeError();
  214.         if(sscanf(++tmstr,"%ld%1s",&value,×ymbol) < 2)
  215.             TimeError();
  216.         switch(toupper(timesymbol))
  217.         {    case 'M':    atti += value * 60L;
  218.                         break;
  219.             case 'H':    atti += value * 3600L;
  220.                         break;
  221.             case 'D':    atti += value * 3600L * 24L;
  222.                         break;
  223.             case 'W':    atti += value * 3600L * 24L * 7L;
  224.                         break;
  225.             default:    TimeError();
  226.         }
  227.         attm = localtime(&atti);
  228.     }
  229.     else
  230.     {    attm = localtime(&curti);
  231.         if(sscanf(timemask,"%d:%d",&attm->tm_hour,&attm->tm_min) < 2)
  232.             TimeError();
  233.  
  234.         if((dtstr=strchr(timemask,' ')) != NULL)
  235.         {    if(sscanf(dtstr,"%d-%d",&attm->tm_mday,&attm->tm_mon) < 2)
  236.                 TimeError();        
  237.             attm->tm_mon--;    /* months are from 0-11 */
  238.         }
  239.         if((atti = mktime(attm)) < curti)
  240.         {    if(dtstr == NULL)
  241.             {    atti += 3600L * 24L;    /* next day */
  242.                 attm = localtime(&atti);
  243.             }
  244.             else
  245.                 attm->tm_year++;        /* next year */
  246.                 atti = mktime(attm);
  247.                 attm = localtime(&atti);
  248.         }
  249.     }
  250.     return attm;
  251. }
  252.  
  253. static void NewJobCmd(char *User,int argc,char *argv[])
  254. {    extern    errno;
  255.     char    atname[MAX_FNAME];
  256.     char    atcmd[MAX_COMMAND];
  257.     char    timemask[MAX_TEMPSTR];
  258.     int        x,charcnt=0,jobcnt=0;
  259.     FILE    *atjob;
  260.     struct tm *attm;
  261.     char    c;
  262.  
  263.     for(x=0;x<argc && strlen(timemask) < (MAX_TEMPSTR - 1);x++)
  264.     {    strcat(timemask,argv[x]);    /* concatenate into one string */
  265.         if(x<argc-1)
  266.             strcat(timemask," ");    /* not after last argv */
  267.     }
  268.  
  269.     while(jobcnt < 1000) /* range from 000 to 999 */
  270.     {    sprintf(atname, "%s/%s.%03d", ATDIR, User, jobcnt);
  271.         if(fopen(ux2dos(atname),"r") == NULL)
  272.             break;    /* unused entry found */
  273.         jobcnt++;
  274.     }
  275.     if(jobcnt >= 1000)
  276.     {    fprintf(stderr,"Max. number of jobs reached (1000)\n");
  277.         exit(1);
  278.     }
  279.     
  280.     ParseJobTime(timemask);
  281.     /* Check time to prevent typing your command for nothing ! */
  282.  
  283.     while(read(fileno(stdin),&c,1),c != '\4' && charcnt < MAX_COMMAND - 1)
  284.     {    /* CR or LF also end a command in this at implementation */
  285.         if(c == '\n' || c == '\r')
  286.             break;
  287.         atcmd[charcnt++] = c;
  288.     }
  289.  
  290.     attm = ParseJobTime(timemask);
  291.     /* After reading command, to avoid starttime is already old ! */
  292.  
  293.     if((atjob=fopen(atname,"w")) == NULL)
  294.     {    fprintf(stderr,"Write failed for %s\n",atname);
  295.         exit(1);
  296.     }
  297.  
  298.     fprintf(atjob,"%02d %02d %02d %02d %02d %s\n",attm->tm_min,
  299.     attm->tm_hour,attm->tm_mday,attm->tm_mon+1,attm->tm_wday,atcmd);
  300.  
  301.     fclose(atjob);
  302.  
  303.     attm->tm_sec=0;
  304.     printf("\nJob %d wil be started at %s",jobcnt,asctime(attm));
  305.     
  306.     PokeDaemon(EXTERNBUILD);    /* send reread signal to daemon */
  307. }
  308.  
  309. void main(int argc,char *argv[])
  310. {    static int    JobId;
  311.     static char    User[MAX_UNAME];
  312.     int skip;
  313.  
  314.     if(argc <= 1) usage();
  315.  
  316.     skip = ParseArgs(argc, argv, User, &JobId);
  317.     argv += skip;
  318.     argc -= skip;
  319.     
  320.     switch (Option)
  321.     {
  322.         case list    :    ListCmd(User);            break;
  323.         case delete    :    DeleteCmd(User,JobId);    break;
  324.         case newjob    :    NewJobCmd(User,argc,argv);        break;
  325.         default        :    usage();                break;
  326.     }
  327.     exit(0);
  328. }
  329.